package com.tencent.cloud.iov.action;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 注解行为执行类：通过注解方式定义具体行为实现方法
 *
 * 对于需要执行目标行为的方法，只需要在方法上添加 @Action(YOUR_ACTION_ID)，
 * 重新编译后，便会生成对应的行为分发类，此类将通过该行为分发类将目标行为分发至具体行为实现方法
 *
 * @author showxiao
 * @date 2018/5/7
 */

public class AnnotationActionHandler implements IActionHandler {

    private static final String CLASS_NAME_POSTFIX = "$ActionDispatcher";
    private static final String METHOD_NAME = "dispatch";

    private Map<Class<?>, List<Method>> mCachedDispatchMethods = new HashMap<>();

    @Override
    public boolean handleAction(Object target, String actionId, Object... args) {
        Class<?> clazz = target.getClass();

        try {
            List<Method> methods = mCachedDispatchMethods.get(clazz);
            if (methods == null) {
                long time = System.currentTimeMillis();
                methods = new ArrayList<>();
                collectGeneratedDispatchMethods(clazz, methods);
                time = System.currentTimeMillis() - time;
                System.out.println("collectGeneratedDispatchMethods: " + time);

                mCachedDispatchMethods.put(clazz, methods);
            }

            if (!methods.isEmpty()) {
                for (Method method : methods) {
                    boolean handled = (boolean) method.invoke(null, target, actionId, args);
                    if (handled) {
                        return true;
                    }
                }
                throw new IllegalStateException("No action is defined for " + target  + " with " +
                        "actionId[" + actionId + "]");
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }

        throw new IllegalStateException("Missing @Action annotation for " + target + " with " +
                "actionId[" + actionId + "]");
    }

    /**
     * 获取编译时注解生成的 dispatch 方法
     *
     * 如果当前类未生成行为分发类，则查找当前类接口或父类生成的行为分发类
     *
     * @param clazz
     * @param methods
     * @return
     */
    private void collectGeneratedDispatchMethods(Class<?> clazz, List<Method> methods) {
        String name = clazz.getName();
        try {
            // 查找当前类
            Class<?> dispatcherClass = Class.forName(name + CLASS_NAME_POSTFIX);
            Method method = dispatcherClass.getDeclaredMethod(METHOD_NAME, clazz, String.class,
                    Object[].class);

            if (method != null) {
                if (!method.isAccessible()) {
                    method.setAccessible(true);
                }
                methods.add(method);
            }
        } catch (ClassNotFoundException e) {
            // do nothing
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } finally {
            collectSuperGeneratedMethods(clazz, methods);
        }
    }

    private void collectSuperGeneratedMethods(Class<?> clazz, List<Method> methods) {
        // 查找接口
        Class<?>[] interfaces = clazz.getInterfaces();
        if (interfaces != null && interfaces.length > 0) {
            for (Class<?> inter : interfaces) {
                collectGeneratedDispatchMethods(inter, methods);
            }
        }

        // 配查找父类
        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null) {
            collectGeneratedDispatchMethods(superclass, methods);
        }
    }
}
